package model

import (
	"context"
	"errors"
	"fmt"
	"haodayizhi/global"
	mtype "haodayizhi/types"
	util "haodayizhi/utils"
	"strconv"
	"strings"
	"time"

	"github.com/go-redis/redis/v8"
	"gorm.io/gorm"
)

const TableNameUser = "users"

// User mapped from table <users>
type User struct {
	ID        int64          `gorm:"column:id;type:bigint;primaryKey;autoIncrement:true" json:"id,string"`
	Username  string         `gorm:"column:username;type:varchar(255)" json:"username"`
	Password  string         `gorm:"column:password;type:varchar(255)" json:"password"`
	Age       int64          `gorm:"column:age;type:int" json:"age"`
	Birth     *time.Time     `gorm:"column:birth;type:date" json:"birth"`
	Gender    int64          `gorm:"column:gender;type:type:tinyint(0)" json:"gender"`
	Signature string         `gorm:"column:signature;type:text" json:"signature"`
	Email     string         `gorm:"column:email;type:varchar(255)" json:"email"`
	Cellphone string         `gorm:"column:cellphone;type:varchar(20)" json:"cellphone"`
	AvatarURL string         `gorm:"column:avatar_url;type:text" json:"avatarUrl"`
	CreatedAt *time.Time     `gorm:"column:created_at;comment:创建时间" json:"createdAt"`
	UpdatedAt *time.Time     `gorm:"column:updated_at;comment:更新时间" json:"updatedAt"`
	DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp" json:"deletedAt"`
	IsRemoved int64          `gorm:"column:is_removed;type:tinyint(1)" json:"isRemoved"`
}

func ConvertUserToResponse(user User) *mtype.UserResponse {
	return &mtype.UserResponse{
		ID:        user.ID,
		Username:  user.Username,
		Age:       user.Age,
		Birth:     user.Birth,
		Gender:    user.Gender,
		Signature: user.Signature,
		Email:     user.Email,
		Cellphone: user.Cellphone,
		AvatarURL: user.AvatarURL,
		CreatedAt: user.CreatedAt,
		UpdatedAt: user.UpdatedAt,
	}
}

// TableName User's table name
func (*User) TableName() string {
	return TableNameUser
}

// CreateUser creates a new User in the database.
func (m *User) CreateUser() error {
	if err := global.Db.Create(m).Error; err != nil {
		return err
	}
	return nil
}

// GetUserByID retrieves a User by its ID from the database.
func (m *User) GetUserByID(id int64) (*User, error) {
	result := global.Db.First(m, id)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return nil, nil // User not found
		}
		return nil, result.Error
	}

	return m, nil
}

// GetUserByEmail retrieves a User by its Email from the database.
func GetUserByEmail(email string) (*User, error) {
	m := &User{}
	result := global.Db.Where("email = ?", email).First(&m)
	if result.Error != nil {
		return nil, result.Error
	}
	return m, nil
}

// GetUserByCellphone retrieves a User by its Cellphone from the database.
func GetUserByCellphone(cellphone string) (*User, error) {
	m := &User{}
	result := global.Db.Where("cellphone = ?", cellphone).First(&m)
	if result.Error != nil {
		return nil, result.Error
	}
	return m, nil
}

// UpdateUser updates an existing User in the database.
func (m *User) UpdateUser() error {
	if err := global.Db.Save(m).Error; err != nil {
		return err
	}
	return nil
}

// DeleteUser deletes a User by its ID from the database.
func (m *User) DeleteUser(id int64) error {
	if err := global.Db.Delete(m, id).Error; err != nil {
		return err
	}
	return nil
}

func AuthenticateUser(username, password string) (*User, error) {
	var user User
	result := global.Db.Where("username = ?", username).First(&user)
	if result.Error != nil {
		return nil, result.Error
	}
	if !util.CheckPassword(user.Password, password) {
		return nil, fmt.Errorf("invalid credentials")
	}
	return &user, nil
}

// 获取用户列表 还要返回到列表总长度

func GetUserList(page, pageSize int) ([]mtype.UserResponse, int64, error) {
	var users []User
	var total int64
	result := global.Db.Offset((page - 1) * pageSize).Limit(pageSize).Find(&users)
	if result.Error != nil {
		return nil, total, result.Error
	}
	filtterUser := []mtype.UserResponse{}
	// 过滤掉密码
	for _, user := range users {
		filtterUser = append(filtterUser, *ConvertUserToResponse(user))
	}

	// 获取总长度
	global.Db.Model(&User{}).Count(&total)
	return filtterUser, total, nil
}

// 根据关键词搜索用户生成列表 可以根据用户名，以及邮箱，手机号搜索，返回列表和总长度
func SearchUser(page, pageSize int, keyword string) ([]mtype.UserResponse, int64, error) {
	var users []User
	var total int64
	result := global.Db.Where("username LIKE ? OR email LIKE ? OR cellphone LIKE ?", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%").Offset((page - 1) * pageSize).Limit(pageSize).Find(&users)
	if result.Error != nil {
		return nil, total, result.Error
	}
	filtterUser := []mtype.UserResponse{}
	// 过滤掉密码
	for _, user := range users {
		filtterUser = append(filtterUser, *ConvertUserToResponse(user))
	}
	// 获取总长度
	global.Db.Model(&User{}).Count(&total)
	return filtterUser, total, nil
}

type UserSearchOnlyIdAndEmail struct {
	ID       int64  `json:"id"`
	Username string `json:"username"`
	Email    string `json:"email"`
}

// 根据关键词搜索用户生成只有用户只有id以及邮箱的列表，可以根据用户名，以及邮箱，手机号搜索，返回列表和总长度
func (m *User) SearchUserOnlyIdAndEmail(page, pageSize int, keyword string) ([]UserSearchOnlyIdAndEmail, int64, error) {
	var users []UserSearchOnlyIdAndEmail
	var total int64
	result := global.Db.Model(&m).Select("email", "id", "username").Where("username LIKE ? OR email LIKE ? OR cellphone LIKE ?", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%").Offset((page - 1) * pageSize).Limit(pageSize).Find(&users)
	if result.Error != nil {
		return nil, total, result.Error
	}
	// 获取总长度
	global.Db.Model(&User{}).Count(&total)
	return users, total, nil
}

var (
	userIDCache      []int64
	cacheLastUpdated time.Time
	cacheExpiry      = time.Minute * 120 // 设置缓存过期时间为 10 分钟
)

func (m *User) GetAllUserIDs() ([]int64, error) {
	rdb := global.Rdb
	ctx := context.Background()
	cachedIDs, err := rdb.Get(ctx, global.AllUserIdKey).Result()
	if err == redis.Nil {
		// 如果 Redis 中没有缓存，从数据库中获取并缓存到 Redis
		err := global.Db.Model(&User{}).Pluck("id", &userIDCache).Error
		if err == nil {
			err = rdb.Set(ctx, global.AllUserIdKey, userIDCache, cacheExpiry).Err()
			return userIDCache, err
		}
		return nil, err
	} else if err != nil {
		return nil, err
	}
	// 如果 Redis 中有缓存，解析缓存数据
	var ids []int64
	for _, idStr := range strings.Split(cachedIDs, ",") {
		id, _ := strconv.ParseUint(idStr, 10, 64)
		ids = append(ids, int64(id))
	}
	return ids, nil
}
